/*
 * Copyright (c) 2021 Zsj. All rights reserved.
 */

package com.jzz.crawlerweb.handler.handler;

import com.jzz.crawlerweb.handler.config.CaptchaHandler;
import com.jzz.crawlerweb.handler.data.Captcha;
import org.reflections.Reflections;
import org.reflections.scanners.SubTypesScanner;
import org.reflections.scanners.TypeAnnotationsScanner;
import org.reflections.util.ConfigurationBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * 抽象验证码处理器
 * <p>
 * 具有生成和核对的功能。如果需要添加其他的验证码处理器，继承{@link AbstractCaptchaHandler}类即可。
 * 子类需要添加<code>@{@link CaptchaHandler}</code>注解。
 * 如果不使用注解，或注解的值为空，则子类的命名需要遵循一定的规范，应当命名为"AbcCaptchaHandler"，其中Abc为自定义内容；在
 * 配置文件中引用时，<code>captcha.type</code>使用abc即可（不区分大小写）。
 */
public abstract class AbstractCaptchaHandler<T> {
    private static final Logger logger = LoggerFactory.getLogger(AbstractCaptchaHandler.class);

    private static Map<String, Class<? extends AbstractCaptchaHandler>> components;

    // 加锁，防止线程冲突
    private static final Object LOCK = new Object();

    public static AbstractCaptchaHandler getInstance(String type) {
        if (components == null) {
            synchronized (LOCK) {
                // 二次校验，防止多次操作
                if (components == null) {
                    components = new HashMap<>();

                    // 进行初始化操作，扫描所有的处理器类
                    Reflections reflections = new Reflections(
                            new ConfigurationBuilder().forPackages("com.jzz.crawlerweb.handler")
                                    .addScanners(new SubTypesScanner())
                                    .addScanners(new TypeAnnotationsScanner())
                    );
                    Set<Class<? extends AbstractCaptchaHandler>> set = reflections.getSubTypesOf(AbstractCaptchaHandler.class);

                    // 遍历所有子类，将其放进Map中
                    for (Class<? extends AbstractCaptchaHandler> cls : set) {
                        String typeName;
                        String clsName = cls.getSimpleName();

                        // 如果有@CaptchaHandler注解，则优先使用注解中的值
                        if (cls.isAnnotationPresent(CaptchaHandler.class)) {
                            CaptchaHandler annotation = cls.getAnnotation(CaptchaHandler.class);
                            typeName = annotation.type().toLowerCase();
                            if (!typeName.isEmpty()) {
                                components.put(typeName, cls);
                                continue;
                            }
                        }

                        if (clsName.endsWith("CaptchaHandler")) {
                            typeName = clsName.substring(0, clsName.lastIndexOf("CaptchaHandler")).toLowerCase();
                            if (!typeName.isEmpty()) {
                                components.put(typeName, cls);
                            }
                        }
                    }
                }
            }
        }

        Class<? extends AbstractCaptchaHandler> clazz = components.get(type.toLowerCase());
        if (clazz != null) {
            try {
                return clazz.getDeclaredConstructor().newInstance();
            } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
                logger.error("Error while creating captcha handler: ", e);
            }
        }
        return null;
    }

    public abstract Captcha<T> generate();

    public boolean verify(String input, String stored) {
        logger.info("Verify input: {}, stored: {}", input, stored);
        return false;
    }

}
